package com.example.nowcodercommunity.service;

import com.example.nowcodercommunity.entity.User;
import com.example.nowcodercommunity.util.RedisKeyUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DataAccessException;
import org.springframework.data.redis.core.RedisOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.SessionCallback;
import org.springframework.stereotype.Service;

import java.util.*;

@Service
public class FollowService {

    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private UserService userService;

    /**
     * 关注
     * @param userId
     * @param entityType
     * @param entityId
     */
    public void follow(int userId,int entityType,int entityId){

        redisTemplate.execute(new SessionCallback() {
            @Override
            public Object execute(RedisOperations operations) throws DataAccessException {
                String followerKey = RedisKeyUtil.getEntityFollowerKey(entityType, entityId);
                String followeeKey = RedisKeyUtil.getUserFolloweeKey(userId, entityType);

                // 启动事务
                operations.multi();
                operations.opsForZSet().add(followerKey, userId, System.currentTimeMillis());
                operations.opsForZSet().add(followeeKey, entityId, System.currentTimeMillis());
                return operations.exec();
            }
        });
    }

    /**
     * 取消关注
     * @param userId
     * @param entityType
     * @param entityId
     */
    public void unFollow(int userId,int entityType,int entityId){

        redisTemplate.execute(new SessionCallback() {
            @Override
            public Object execute(RedisOperations operations) throws DataAccessException {
                String followerKey = RedisKeyUtil.getEntityFollowerKey(entityType, entityId);
                String followeeKey = RedisKeyUtil.getUserFolloweeKey(userId, entityType);

                // 启动事务
                operations.multi();
                operations.opsForZSet().remove(followerKey, userId);
                operations.opsForZSet().remove(followeeKey, entityId);
                return operations.exec();
            }
        });
    }

    /**
     * 获取用户关注某一种类目标的数量
     * 种类可以是用户，帖子等
     * @param userId
     * @param entityType
     * @return
     */
    public long getUserFolloweeCount(int userId, int entityType){
        String followerKey = RedisKeyUtil.getUserFolloweeKey(userId, entityType);

        return redisTemplate.opsForZSet().zCard(followerKey);
    }

    /**
     * 获取实体被关注数量
     * 实体可以是用户，帖子等
     * @param entityId
     * @param entityType
     * @return
     */
    public long getEntityFollowerCount(int entityId, int entityType){
        String followeeKey = RedisKeyUtil.getEntityFollowerKey(entityType, entityId);

        return redisTemplate.opsForZSet().zCard(followeeKey);
    }

    /**
     * 用户是否关注目标实体
     * @param userId
     * @param entityType
     * @param entityId
     * @return
     */
    public boolean hasUserFollowedEntity(int userId, int entityType, int entityId){
        String followeeKey = RedisKeyUtil.getUserFolloweeKey(userId, entityType);

        Double score = redisTemplate.opsForZSet().score(followeeKey, entityId);

        return score != null;
    }

    /**
     * 分页查询某用户的关注列表
     * @param userId
     * @param offset
     * @param limit
     * @return
     */
    public List<Map<String, Object>> getUserFollowee(int userId, int offset, int limit){
        String followeeKey = RedisKeyUtil.getUserFolloweeKey(userId, CommunityConstant.ENTITY_TYPE_USER);
        Set<Integer> set = redisTemplate.opsForZSet().reverseRange(followeeKey, offset, offset + limit - 1);

        if(set == null){
            return null;
        }

        List<Map<String, Object>> followee = new LinkedList<>();
        for(int targetId : set){
            Map<String, Object> map = new HashMap<>();

            User userById = userService.findUserById(targetId);
            map.put("user", userById);

            Double score = redisTemplate.opsForZSet().score(followeeKey, targetId);
            map.put("followTime", new Date(score.longValue()));

            followee.add(map);
        }

        return followee;
    }

    /**
     * 查询用户关注者列表
     * @param userId
     * @param offset
     * @param limit
     * @return
     */
    public List<Map<String, Object>> getUserFollowers(int userId, int offset, int limit){
        String followerKey = RedisKeyUtil.getEntityFollowerKey(CommunityConstant.ENTITY_TYPE_USER, userId);
        Set<Integer> set = redisTemplate.opsForZSet().reverseRange(followerKey, offset, offset + limit - 1);

        if(set == null){
            return null;
        }

        List<Map<String, Object>> followers = new LinkedList<>();
        for(int targetId : set){
            Map<String, Object> map = new HashMap<>();

            User user = userService.findUserById(targetId);
            map.put("user", user);
            Double score = redisTemplate.opsForZSet().score(followerKey, targetId);
            map.put("followTime", new Date(score.longValue()));

            followers.add(map);
        }

        return followers;
    }
}
